//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<data_entry_cache.cpp>
///	@path	~/src/database/xres/
///	@date	2007/12/19
///	@desc	Data entry cache.

#include "config/config.h"

#include "database/xres/data_entry_cache.h"

namespace xeres {

	// DataEntryCache
	DataEntryCache::DataEntryCache( size_t init_cache_size )
		: m_lv1max( init_cache_size )
		, m_lv1size( 0 )
		, m_cache_lv1( NULL )
		, m_cache_lv1_free( NULL )
		, m_cache_lv1_root( NULL )
		, m_cache_lv1_end( NULL )
	{
		ResetCache( init_cache_size );
	}

	// ~DataEntryCache
	DataEntryCache::~DataEntryCache( void )
	{

	}

	// ResetCache
	void DataEntryCache::ResetCache( size_t newSize )
	{
		assert( newSize > 0 );

		// FIXME: clear lv2 here ?

		// free current cache
		ClearCache();
		
		// create new
		m_cache_lv1 = static_cast<_Lv1CacheNode *>(
			_aligned_malloc( newSize * sizeof(_Lv1CacheNode) , ALIGN_SIZE ) );
		m_lv1max = newSize;
		m_lv1size = 0;

		_Lv1CacheNode * root = m_cache_lv1;
		for( size_t i = 0 ; i < m_lv1max ; ++i , ++root )
		{
			new (root) _Lv1CacheNode;
			root->m_lastAccess = 0;
			root->m_hash = 0;
			if( i > 0 )
				root->m_prev = root - 1;
			else
				root->m_prev = NULL;
			root->m_next = root + 1;
		}
		root->m_prev->m_next = NULL;
		m_cache_lv1_free = m_cache_lv1;

		m_cache_lv1_root = NULL;
		m_cache_lv1_end = NULL;
	}

	// ClearCache
	void DataEntryCache::ClearCache( void )
	{
		if( m_cache_lv1 )
		{
			_Lv1CacheNode * root = m_cache_lv1_root;
			while( root )
			{
				_Lv1CacheNode * next = root->m_next;
				root->~_Lv1CacheNode();
				root = next;
			}
			_aligned_free( m_cache_lv1 );
			m_cache_lv1 = m_cache_lv1_free =
				m_cache_lv1_root = m_cache_lv1_end = NULL;
			m_lv1size = 0;
		}
	}

	// SetCacheSize
	void DataEntryCache::SetCacheSize( size_t lv1 , size_t lv2 )
	{
		if( lv1 == 0 || lv2 == 0 )
		{
			TRACE_ERROR( _S("DataEntryCache::SetCacheSize: Cache size cannot be 0.\n") );
			return;
		}

		if( lv1 == m_lv1size )
		{
			return;
		}

		LockGuard<ThreadLock> locker( m_lock );

		ResetCache( lv1 );

		// assign lv2 cache size
		m_lv2max = lv2;
		m_cache_lv2.clear();

		// might optimize lv2 at run time
	}

	// QueryCache
	RefPass<IData> DataEntryCache::QueryCache( const WString& path )
	{
		LockGuard<ThreadLock> locker(m_lock);

/*		// search cache 1 first
		if( m_lv1size > 0 )
		{
			size_t hash = std::hash_value(path);
			_Lv1CacheNode * node = m_cache_lv1_root;
			while( node )
			{
				// compare hash
				if( node->m_hash == hash )
				{
					// and compare string
					if( node->m_path == path )
					{
						// update last access time
						node->m_lastAccess = Time::Now();
						return node->m_entry;
					}
					TRACE_WARNING( _S("DataEntryCache::QueryCache: Duplicate hash value found: '%s' & '%s'.") ,
						node->m_path.c_str() , path.c_str() );
				}
				node = node->m_next;
			}
		}
	*/
		// search lv2
		dict<WString,_Lv2CacheNode>::iterator it = m_cache_lv2.find( path );
		if( it != m_cache_lv2.end() )
		{
			_Lv2CacheNode& node = it->second;
			// update to lv1 if needed
			{

			}
			return node.m_entry;
		}
		return NULL;
	}

	// InsertCache
	void DataEntryCache::InsertCache( const WString& path , RefWeak<IData> data )
	{

	}

	// FlushCache
	void DataEntryCache::FlushCache( void )
	{

	}

} // namespace xeres
